package controllers;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;

import buttons.Button;
import buttons.control.C_Button;
import buttons.view.V_Button;
import buttons.view.V_DoubleSlider;
import utilities.EventListener;
import utilities.EventOwner;
import viz_main.Node;
import viz_main.ScatterPlotCAxis;
import viz_main.TreeComponent;
import viz_ui.TreeMapView;

// Handles interaction with the bar view such as selecting a single bar or mouse-over tooltips of a bar
public class C_TreeMap extends EventOwner implements EventListener{
	
	public static int[] boxColor = {50,220,210};
	
	protected C_TooltipControl c_toolTip;
	protected String tooltipText = "";
	private int selectedIndex = -1;
	private int innerSelected = -1;
	private int overIndex = -1;
	boolean wasOver = false;

	public C_TreeMap(TreeMapView view, ControlManager manager, C_TooltipControl toolTipController)
	{
		vFeature = view;
		c_toolTip = toolTipController;
		controlManager = manager;
		controlManager.addController(this);
	}
	
	@Override
	public void onInteract (float mouseXLoc, float mouseYLoc, String interID)
	{
		TreeMapView treeView = (TreeMapView)vFeature;
		overIndex = -1;
		
		// if the mouse is within the tree view's bounds...
		if(mouseXLoc > treeView.getXLoc() && mouseXLoc < treeView.getXLoc() + treeView.getXSize())
		{
			if(mouseYLoc > treeView.getYLoc() && mouseYLoc < treeView.getYLoc() + treeView.getYSize())
			{
				// check if mouse is within bounds of one of the nodes:
				for(int i = 0; i < treeView.getAllBoxes().size(); i++)
				{
					TreeComponent workingBox = treeView.getAllBoxes().get(i);
					if(mouseXLoc > workingBox.getXLoc() && mouseXLoc < workingBox.getXLoc()+workingBox.getXSize() 
							&& mouseYLoc > workingBox.getYLoc() && mouseYLoc < workingBox.getYLoc()+workingBox.getYSize())
					{
						overIndex = i;
					}
				}
				
				// if it is, then we can enable a tooltip
				if(overIndex > -1)
				{
					tooltipText = treeView.getAllBoxes().get(overIndex).getNode().getName();
					wasOver = true;
				}
				// if it isn't then we should disable tooltip
				else {
					disableTooltipOnce();
				}
			}
			else disableTooltipOnce();
		}
		else disableTooltipOnce();

		// Handle Mouse click events:
		if(interID.equals("leftClick"))
		{
			if(overIndex > -1)
			{
				if(overIndex != selectedIndex)
				{
					deselect();
					deselectInner();
					treeView.getAllBoxes().get(overIndex).setSelected(true);

					//set the names to be displayed underneath the treeMap
					//if (treeView.getAllBoxes().get(overIndex).getNode().getParent().getName().equals("Streets")){
					treeView.setdisplayInfo(treeView.getAllBoxes().get(overIndex).getNode().getName(), " ", " ");
					//}
					//else
					//treeView.setdisplayInfo(treeView.getAllBoxes().get(overIndex).getNode().getParent().getName(), treeView.getAllBoxes().get(overIndex).getNode().getName(), " ");
					
					System.out.println(treeView.getAllBoxes().get(overIndex).getNode().getName());
					selectedIndex = overIndex;
					triggerEvent("@Selected");
				}
				// if selecting the same object as previous, then toggle it off
				else {
					deselect();
					treeView.setdisplayInfo(" ", " ", " ");

				}
			}
			// if clicking outside of the view, turn off selection
			else {
				//deselect();
				treeView.setdisplayInfo(" ", " ", " ");
			}
		}
		
		// RIGHTCLICK allows user to select an inner node for more granularity
		else if(interID.equals("rightClick"))
		{
			overIndex = -1;
			for(int i = 0; i < treeView.getInnerBoxes().size(); i++){
				TreeComponent workingBox = treeView.getInnerBoxes().get(i);
				if(mouseXLoc > workingBox.getXLoc() && mouseXLoc < workingBox.getXLoc()+workingBox.getXSize() 
						&& mouseYLoc > workingBox.getYLoc() && mouseYLoc < workingBox.getYLoc()+workingBox.getYSize())
				{
					overIndex = i;
				}
			}
			
			if(overIndex > -1)
			{
				if(overIndex != innerSelected)
				{
					deselectInner();
					deselect();
					treeView.getInnerBoxes().get(overIndex).setSelected(true);

					//set the names to be displayed underneath the treeMap
					treeView.setdisplayInfo(treeView.getInnerBoxes().get(overIndex).getNode().getParent().getName(), treeView.getInnerBoxes().get(overIndex).getNode().getName(), " ");
					
					System.out.println(treeView.getInnerBoxes().get(overIndex).getNode().getName());
					innerSelected = overIndex;
					triggerEvent("@InnerSelected");
				}
				// if selecting the same object as previous, then toggle it off
				else {
					deselectInner();
					treeView.setdisplayInfo(" ", " ", " ");

				}
			}
			// if clicking outside of the view, turn off selection
			else {
				deselectInner();
				treeView.setdisplayInfo(" ", " ", " ");
			}
		}
		
		handleTooltip(mouseXLoc, mouseYLoc);
	}
	
	public void disableTooltipOnce()
	{
		if(wasOver)
		{
			tooltipText = "";
			wasOver = false;
		}
	}
	
	public void deselect()
	{
		if(selectedIndex > -1)
		{
			((TreeMapView)vFeature).getAllBoxes().get(selectedIndex).setSelected(false);
			selectedIndex = -1;
			triggerEvent("@Deselected");
		}
	}
	
	public void deselectInner()
	{
		if(innerSelected > -1)
		{
			((TreeMapView)vFeature).getInnerBoxes().get(innerSelected).setSelected(false);
			innerSelected = -1;
			triggerEvent("@Deselected");
		}
	}
	
	// deSelects components without triggering an event
	public void softDeselectAll()
	{
		if(selectedIndex > -1)
		{
			((TreeMapView)vFeature).getAllBoxes().get(selectedIndex).setSelected(false);
			selectedIndex = -1;
		}
		
		if(innerSelected > -1)
		{
			((TreeMapView)vFeature).getInnerBoxes().get(innerSelected).setSelected(false);
			innerSelected = -1;
		}
	}
	
	public void deselectAll()
	{
		if(selectedIndex > -1)
		{
			((TreeMapView)vFeature).getAllBoxes().get(selectedIndex).setSelected(false);
			selectedIndex = -1;
		}
		
		if(innerSelected > -1)
		{
			((TreeMapView)vFeature).getInnerBoxes().get(innerSelected).setSelected(false);
			innerSelected = -1;
		}
		triggerEvent("@Deselected");
	}
	
	// TODO: revise this logic
	private void handleTooltip(float mouseXLoc, float mouseYLoc)
	{
		if(c_toolTip.checkForTip(mouseXLoc, mouseYLoc))
        {
            if(tooltipText.length() > 0) // if the button HAS a set tooltip display it
            {
              c_toolTip.setName(tooltipText);
              c_toolTip.setActive(true);
            }
        }
        else c_toolTip.setActive(false);
	}

	@Override
	// Handle events triggered by the buttons of this controllers vFeature.
	// this includes filtering and switching the x-axis.
	public void handleEvent(String trigger, EventOwner obj) {
		TreeMapView treeView = (TreeMapView)vFeature;
		
		if(trigger.startsWith("@"))
		{
			C_BarView barController = (C_BarView)obj;
			// COLOR CODE the TreeMap:
			if(trigger.equals("@Selected"))
			{
				deselectAll();
				// get the category in question: 
				String category = barController.getSelectedCategory();
				System.out.print(category + " is selected. ");
				ScatterPlotCAxis attributeAxis = barController.getActiveAxis();
				
				// each node in the tree map has 0 or more data-cases with that category.
				// we want to use the opacity value of a color as an encoding mechanism to show 
				// the relative amount per-node.
				
				// like how the nodes are initially drawn, it should be based on percent of the total.
				// first we need to compute that total.
				float total = 0;
				ArrayList<Node> nodeGroup = treeView.getTree().getChildren();
				for(int i = 0; i < nodeGroup.size(); i++)
				{
					if(nodeGroup.get(i).getRecordOf(category) == null)
					{
						nodeGroup.get(i).createNewRecordOf(attributeAxis, category);
					}
					total += nodeGroup.get(i).getRecordOf(category).length;
				}
				System.out.println(total + " indexes contain that category."); 
				
				// then we determine percent based on (count/total) where count is the number of indexes that contain 
				// that value. Lastly we map that percentage to opacity.
				for(int i = 0; i < treeView.getAllBoxes().size(); i++)
				{
					TreeComponent workingBox = treeView.getAllBoxes().get(i);
					//System.out.println(workingBox.getNode().getRecordOf(category).length);
					float percent = (workingBox.getNode().getRecordOf(category).length/total)*10;
					System.out.println(percent);
					//int color = boxColor >> 16 & 0xFF, boxColor >> 8 & 0xFF, boxColor & 0xFF);
					workingBox.setBGColor(new Color(boxColor[0], boxColor[1], boxColor[2]));
					//workingBox.setBGColor(new Color(boxColor[0]*percent, boxColor[1]*percent, boxColor[2]*percent));
					if(workingBox.getNode().getRecordOf(category).length >= 1)
					{
						percent = Math.max(percent, 0.1f);
					}
					workingBox.setOpacity(percent);
				}
			}
			else if(trigger.equals("@Deselected"))
			{
				// reset all components so they are back to normal display with no color:
				for(int i = 0; i < treeView.getAllBoxes().size(); i++)
				{
					TreeComponent workingBox = treeView.getAllBoxes().get(i);
					workingBox.setBGColor(new Color(255, 255, 255));
					workingBox.setOpacity(TreeComponent.BASE_ALPHA);
				}
			}
		}
		
		else {
			String buttonName = ( (V_Button)((C_Button)obj).getView() ).getName();
		}
	}
	
	public Node getSelectedNode()
	{
		return ((TreeMapView)vFeature).getAllBoxes().get(selectedIndex).getNode();
	}
	
	public Node getInnerSelectedNode()
	{
		return ((TreeMapView)vFeature).getInnerBoxes().get(innerSelected).getNode();
	}
	
	public Node getAnySelectedNode()
	{
		if(selectedIndex > -1)
		{
			return ((TreeMapView)vFeature).getAllBoxes().get(selectedIndex).getNode();
		}
		else if (innerSelected > -1)
		{
			return ((TreeMapView)vFeature).getInnerBoxes().get(innerSelected).getNode();
		}
		else return null;
	}
}
